// ============================================================================
// 错误边界组件
// ============================================================================

import React, { Component, ErrorInfo, ReactNode } from 'react'
import { ExclamationTriangleIcon, ArrowPathIcon, ClipboardDocumentIcon } from '@heroicons/react/24/outline'
import { errorHandler, ErrorCode, ErrorSeverity, createError } from '../../utils/error-handler'
import { logger } from '../../utils/logger'
import { Button } from './button'

interface Props {
  children: ReactNode
  fallback?: ReactNode
  onError?: (error: Error, errorInfo: ErrorInfo) => void
  showDetails?: boolean
  component?: string
}

interface State {
  hasError: boolean
  error?: Error
  errorInfo?: ErrorInfo
  errorId?: string
}

/**
 * 错误边界组件 - 增强版
 * 捕获子组件中的JavaScript错误并显示友好的错误界面
 */
export class ErrorBoundary extends Component<Props, State> {
  private componentLogger = logger

  constructor(props: Props) {
    super(props)
    this.state = { hasError: false }
  }

  static getDerivedStateFromError(error: Error): State {
    return {
      hasError: true,
      error,
      errorId: `error_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`
    }
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    this.setState({ errorInfo })

    // 创建应用错误
    const appError = createError(
      ErrorCode.INTERNAL_ERROR,
      `Component error in ${this.props.component || 'unknown component'}: ${error.message}`,
      ErrorSeverity.HIGH,
      {
        component: this.props.component || 'unknown',
        metadata: {
          componentStack: errorInfo.componentStack
        }
      }
    )

    // 处理错误
    errorHandler.handle(appError)

    // 记录详细日志
    this.componentLogger.error('Component error caught', {
      error: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack,
      errorId: this.state.errorId
    }, error)

    // 调用外部错误处理器
    this.props.onError?.(error, errorInfo)
  }

  handleReload = () => {
    this.componentLogger.info('User initiated page reload', { errorId: this.state.errorId })
    window.location.reload()
  }

  handleReset = () => {
    this.componentLogger.info('User initiated retry', { errorId: this.state.errorId })
    this.setState({ hasError: false })
  }

  handleReportError = () => {
    const { error, errorInfo, errorId } = this.state

    if (error && errorInfo) {
      const errorReport = {
        errorId,
        message: error.message,
        stack: error.stack,
        componentStack: errorInfo.componentStack,
        timestamp: new Date().toISOString(),
        userAgent: navigator.userAgent,
        url: window.location.href
      }

      // 复制错误报告到剪贴板
      navigator.clipboard.writeText(JSON.stringify(errorReport, null, 2))
        .then(() => {
          alert('错误报告已复制到剪贴板')
        })
        .catch(() => {
          console.error('Failed to copy error report')
        })
    }
  }

  render() {
    if (this.state.hasError) {
      // 如果提供了自定义fallback，使用它
      if (this.props.fallback) {
        return this.props.fallback
      }

      // 默认错误界面
      return (
        <div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center p-4">
          <div className="max-w-md w-full bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6 text-center">
            <div className="w-16 h-16 bg-red-100 dark:bg-red-900/20 rounded-full flex items-center justify-center mx-auto mb-4">
              <ExclamationTriangleIcon className="w-8 h-8 text-red-600 dark:text-red-400" />
            </div>
            
            <h1 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
              应用出现错误
            </h1>
            
            <p className="text-gray-600 dark:text-gray-400 mb-6">
              很抱歉，应用遇到了一个意外错误。您可以尝试重新加载页面或重置应用状态。
            </p>

            {/* 错误详情（开发模式下显示） */}
            {process.env.NODE_ENV === 'development' && this.state.error && (
              <details className="text-left mb-6 p-4 bg-gray-100 dark:bg-gray-700 rounded-lg">
                <summary className="cursor-pointer font-medium text-gray-900 dark:text-white mb-2">
                  错误详情
                </summary>
                <pre className="text-xs text-red-600 dark:text-red-400 overflow-auto">
                  {this.state.error.toString()}
                  {this.state.errorInfo?.componentStack}
                </pre>
              </details>
            )}
            
            <div className="flex flex-col sm:flex-row gap-3">
              <Button
                onClick={this.handleReset}
                variant="secondary"
                className="flex-1"
              >
                重试
              </Button>

              <Button
                onClick={this.handleReload}
                variant="primary"
                className="flex-1"
                icon={<ArrowPathIcon className="w-4 h-4" />}
              >
                重新加载
              </Button>

              {(this.props.showDetails || process.env.NODE_ENV === 'development') && (
                <Button
                  onClick={this.handleReportError}
                  variant="outline"
                  className="flex-1"
                  icon={<ClipboardDocumentIcon className="w-4 h-4" />}
                >
                  复制错误报告
                </Button>
              )}
            </div>
          </div>
        </div>
      )
    }

    return this.props.children
  }
}

/**
 * 高阶组件：为组件添加错误边界
 */
export function withErrorBoundary<P extends object>(
  Component: React.ComponentType<P>,
  errorBoundaryProps?: Omit<Props, 'children'>
) {
  const WrappedComponent = (props: P) => (
    <ErrorBoundary {...errorBoundaryProps}>
      <Component {...props} />
    </ErrorBoundary>
  )

  WrappedComponent.displayName = `withErrorBoundary(${Component.displayName || Component.name})`

  return WrappedComponent
}

/**
 * 函数式错误边界Hook（用于函数组件）
 */
export function useErrorHandler() {
  return (error: Error, _errorInfo?: ErrorInfo) => {
    const appError = createError(
      ErrorCode.INTERNAL_ERROR,
      error.message,
      ErrorSeverity.HIGH,
      {
        component: 'FunctionComponent'
      }
    )

    errorHandler.handle(appError)
  }
}
